package client

import (
	"context"
	"fmt"
	"meta-self/internal/consts"
	"meta-self/internal/dao"
	"meta-self/internal/model/entity"
	"meta-self/internal/model/input/clientin"
	"meta-self/internal/pkg/contexts"
	"meta-self/internal/service"
	"time"

	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/grand"
)

type sLicenseKey struct{}

func init() {
	service.RegisterLicenseKey(&sLicenseKey{})
}

// Model 卡密ORM模型
func (s *sLicenseKey) Model(ctx context.Context) *gdb.Model {
	return dao.SysLicenseKeys.Ctx(ctx)
}

// HistoryModel 卡密历史记录ORM模型
func (s *sLicenseKey) HistoryModel(ctx context.Context) *gdb.Model {
	return dao.SysLicenseKeyHistory.Ctx(ctx)
}

// CalcPrice 计算卡密价格
func (s *sLicenseKey) CalcPrice(ctx context.Context, in *clientin.LicenseKeyCalcPriceInp) (res *clientin.LicenseKeyCalcPriceModel, err error) {
	// 根据时长计算价格，这里设置基础价格，实际业务中可能有更复杂的计算逻辑
	// 例如：不同时长对应不同的单价，或者有折扣规则等
	var basePrice float64 = 10.0 // 基础日单价
	var price float64 = 0.0

	// 简单的计价规则示例
	// 假设时长1-30天，每天10元
	// 30-90天，每天9元
	// 90-180天，每天8元
	// 180天以上，每天7元
	if in.DurationDays <= 30 {
		price = float64(in.DurationDays) * basePrice
	} else if in.DurationDays <= 90 {
		price = float64(in.DurationDays) * 9.0
	} else if in.DurationDays <= 180 {
		price = float64(in.DurationDays) * 8.0
	} else {
		price = float64(in.DurationDays) * 7.0
	}

	// 返回计算结果
	res = &clientin.LicenseKeyCalcPriceModel{
		Price: price,
	}
	return
}

// CreateOrder 创建卡密订单
func (s *sLicenseKey) CreateOrder(ctx context.Context, in *clientin.LicenseKeyCreateOrderInp) (res *clientin.LicenseKeyCreateOrderModel, err error) {
	// 1. 计算价格
	priceModel, err := s.CalcPrice(ctx, &clientin.LicenseKeyCalcPriceInp{
		DurationDays: in.DurationDays,
		Email:        in.Email,
	})
	if err != nil {
		return nil, err
	}

	// 2. 生成卡密信息
	// 用于确保订单支付后能找到对应的卡密进行激活
	var licenseKeyId uint64 = 0

	err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		// 生成随机卡密字符串
		keyString := s.generateKeyString()

		// 检查卡密是否已存在
		var count int
		count, err = s.Model(ctx).Where(dao.SysLicenseKeys.Columns().KeyString, keyString).Count()
		if err != nil {
			return err
		}
		if count > 0 {
			return gerror.New("卡密生成冲突，请重试")
		}

		// 创建待激活卡密
		result, err := s.Model(ctx).Data(entity.SysLicenseKeys{
			KeyString:    keyString,
			Email:        in.Email,
			Status:       consts.LicenseKeyStatusPending, // 待激活
			DurationDays: in.DurationDays,
			Price:        priceModel.Price,
			CreatedAt:    gtime.Now(),
			UpdatedAt:    gtime.Now(),
		}).Insert()
		if err != nil {
			return err
		}

		// 获取新插入的卡密ID
		lastId, err := result.LastInsertId()
		if err != nil {
			return err
		}
		licenseKeyId = uint64(lastId)

		// 添加创建历史记录
		_, err = s.HistoryModel(ctx).Insert(entity.SysLicenseKeyHistory{
			LicenseKeyId:      licenseKeyId,
			ActionType:        consts.LicenseKeyActionCreate,
			Description:       "创建待激活卡密",
			DurationDaysAdded: int(in.DurationDays),
			CreatedAt:         gtime.Now(),
		})
		if err != nil {
			return err
		}

		return nil
	})

	if err != nil {
		return nil, gerror.Wrap(err, consts.ErrLicenseKeyCreateFailed)
	}

	// 3. 创建支付订单
	orderModel, err := service.SysOrder().Create(ctx, &clientin.OrderCreateInp{
		OrderType: consts.OrderTypeProduct,
		ProductId: int64(licenseKeyId), // 使用卡密ID作为产品ID
		Money:     priceModel.Price,
		PayType:   in.PayType,
		TradeType: in.TradeType,
		ReturnUrl: in.ReturnUrl,
		Remark:    fmt.Sprintf("购买卡密服务: %d天", in.DurationDays),
	})
	if err != nil {
		return nil, err
	}

	// 4. 更新卡密记录，关联订单ID
	_, err = s.Model(ctx).Where(dao.SysLicenseKeys.Columns().Id, licenseKeyId).Data(g.Map{
		dao.SysLicenseKeys.Columns().OrderId: orderModel.Order,
	}).Update()
	if err != nil {
		g.Log().Error(ctx, "更新卡密订单ID失败:", err)
		// 这里不返回错误，因为卡密已创建，支付订单也已创建，只是关联关系没建立，不影响主流程
	}

	// 返回支付订单信息
	res = &clientin.LicenseKeyCreateOrderModel{
		Order: orderModel.Order,
	}
	return
}

// Activate 激活卡密（仅供系统内部调用）
func (s *sLicenseKey) Activate(ctx context.Context, in *clientin.LicenseKeyActivateInp) (res *clientin.LicenseKeyActivateModel, err error) {
	var licenseKey *entity.SysLicenseKeys
	// 查询卡密是否存在
	if err = s.Model(ctx).Where(dao.SysLicenseKeys.Columns().KeyString, in.KeyString).Scan(&licenseKey); err != nil {
		return nil, err
	}

	if licenseKey == nil {
		return nil, gerror.New(consts.ErrLicenseKeyNotFound)
	}

	// 检查卡密状态
	if licenseKey.Status != consts.LicenseKeyStatusPending {
		switch licenseKey.Status {
		case consts.LicenseKeyStatusActive:
			return nil, gerror.New(consts.ErrLicenseKeyActivated)
		case consts.LicenseKeyStatusExpired:
			return nil, gerror.New(consts.ErrLicenseKeyExpired)
		case consts.LicenseKeyStatusRefunded:
			return nil, gerror.New("卡密已退款")
		default:
			return nil, gerror.New(consts.ErrLicenseKeyInvalid)
		}
	}

	// 如果提供了邮箱，优先使用邮箱
	email := in.Email
	if email == "" && licenseKey.Email != "" {
		email = licenseKey.Email
	}

	// 如果提供了用户ID，优先使用用户ID
	userId := in.UserId
	if userId <= 0 {
		// 如果没有用户ID，检查是否能通过邮箱关联到用户
		if email != "" {
			var user *entity.SysUser
			err = dao.SysUser.Ctx(ctx).Where(dao.SysUser.Columns().Email, email).Scan(&user)
			if err != nil {
				return nil, err
			}

			if user != nil {
				userId = user.Id
			}
		}
	}

	// 事务处理
	err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		now := gtime.Now()
		expiresAt := now.Add(time.Hour * 24 * time.Duration(licenseKey.DurationDays))

		// 更新卡密状态
		updateData := g.Map{
			dao.SysLicenseKeys.Columns().Status:      consts.LicenseKeyStatusActive,
			dao.SysLicenseKeys.Columns().ActivatedAt: now,
			dao.SysLicenseKeys.Columns().ExpiresAt:   expiresAt,
			dao.SysLicenseKeys.Columns().UpdatedAt:   now,
		}

		// 如果有用户ID则进行关联
		if userId > 0 {
			updateData[dao.SysLicenseKeys.Columns().UserId] = userId
		}

		_, err = s.Model(ctx).
			Where(dao.SysLicenseKeys.Columns().Id, licenseKey.Id).
			Data(updateData).Update()
		if err != nil {
			return err
		}

		// 添加激活历史记录
		historyData := entity.SysLicenseKeyHistory{
			LicenseKeyId:      licenseKey.Id,
			ActionType:        consts.LicenseKeyActionActivate,
			Description:       "支付成功后系统自动激活卡密",
			DurationDaysAdded: int(licenseKey.DurationDays),
			NewExpiresAt:      expiresAt,
			CreatedAt:         now,
		}

		if userId > 0 {
			historyData.UserId = uint64(userId)
		}

		_, err = s.HistoryModel(ctx).Insert(historyData)
		if err != nil {
			return err
		}

		return nil
	})

	if err != nil {
		return nil, gerror.Wrap(err, consts.ErrLicenseKeyActivateFailed)
	}

	// 重新获取卡密信息
	if err = s.Model(ctx).Where(dao.SysLicenseKeys.Columns().KeyString, in.KeyString).Scan(&licenseKey); err != nil {
		return nil, err
	}

	res = &clientin.LicenseKeyActivateModel{
		SysLicenseKeys: *licenseKey,
	}
	return
}

// View 获取卡密详情
func (s *sLicenseKey) View(ctx context.Context, in *clientin.LicenseKeyViewInp) (res *clientin.LicenseKeyViewModel, err error) {
	var licenseKey *entity.SysLicenseKeys
	res = new(clientin.LicenseKeyViewModel)

	// 根据ID查询
	if in.Id > 0 {
		if err = s.Model(ctx).Where(dao.SysLicenseKeys.Columns().Id, in.Id).Scan(&licenseKey); err != nil {
			return nil, err
		}
	} else if in.KeyString != "" {
		// 根据卡密字符串查询
		if err = s.Model(ctx).Where(dao.SysLicenseKeys.Columns().KeyString, in.KeyString).Scan(&licenseKey); err != nil {
			return nil, err
		}
	} else {
		return nil, gerror.New("查询参数不足")
	}

	if licenseKey == nil {
		return nil, gerror.New(consts.ErrLicenseKeyNotFound)
	}

	// 检查用户权限，已登录用户只能查看自己的卡密
	userId := contexts.GetUserId(ctx)
	if userId > 0 && licenseKey.UserId > 0 && licenseKey.UserId != userId {
		// 检查邮箱是否匹配当前登录用户
		var user *entity.SysUser
		err = dao.SysUser.Ctx(ctx).Where(dao.SysUser.Columns().Id, userId).Scan(&user)
		if err != nil {
			return nil, err
		}

		// 如果用户邮箱与卡密邮箱匹配，允许查看
		if user != nil && user.Email != "" && user.Email == licenseKey.Email {
			// 允许查看并自动关联
			_, err = s.Model(ctx).Where(dao.SysLicenseKeys.Columns().Id, licenseKey.Id).Data(g.Map{
				dao.SysLicenseKeys.Columns().UserId: userId,
			}).Update()
			if err != nil {
				g.Log().Error(ctx, "自动关联卡密用户失败:", err)
				// 不返回错误，不影响查询流程
			}
		} else {
			return nil, gerror.New("无权限查看此卡密")
		}
	}

	res.SysLicenseKeys = *licenseKey
	return
}

// List 获取用户卡密列表
func (s *sLicenseKey) List(ctx context.Context, in *clientin.LicenseKeyListInp) (list []*clientin.LicenseKeyListModel, totalCount int, err error) {
	model := s.Model(ctx)

	// 尝试获取当前用户信息
	userId := contexts.GetUserId(ctx)
	if userId > 0 {
		// 已登录用户，查询关联到用户ID的卡密
		model = model.Where(dao.SysLicenseKeys.Columns().UserId, userId)
	} else {
		// 未登录用户，如果提供了邮箱，则按邮箱查询
		if in.Email == "" {
			return nil, 0, gerror.New("未登录用户必须提供邮箱查询")
		}
		model = model.Where(dao.SysLicenseKeys.Columns().Email, in.Email)
	}

	// 按卡密字符串模糊查询
	if in.KeyString != "" {
		model = model.WhereLike(dao.SysLicenseKeys.Columns().KeyString, "%"+in.KeyString+"%")
	}

	// 按状态筛选
	if in.Status != "" {
		model = model.Where(dao.SysLicenseKeys.Columns().Status, in.Status)
	}

	// 按有效时长筛选
	if in.DurationDays > 0 {
		model = model.Where(dao.SysLicenseKeys.Columns().DurationDays, in.DurationDays)
	}

	// 按激活时间范围筛选
	if len(in.ActivatedAt) == 2 && in.ActivatedAt[0] != nil && in.ActivatedAt[1] != nil {
		model = model.WhereBetween(dao.SysLicenseKeys.Columns().ActivatedAt, in.ActivatedAt[0], in.ActivatedAt[1])
	}

	// 按过期时间范围筛选
	if len(in.ExpiresAt) == 2 && in.ExpiresAt[0] != nil && in.ExpiresAt[1] != nil {
		model = model.WhereBetween(dao.SysLicenseKeys.Columns().ExpiresAt, in.ExpiresAt[0], in.ExpiresAt[1])
	}

	// 执行查询
	totalCount, err = model.Count()
	if err != nil {
		return nil, 0, err
	}

	if totalCount == 0 {
		return nil, 0, nil
	}

	if err = model.Page(in.PageReq.Page, in.PageReq.PerPage).OrderDesc(dao.SysLicenseKeys.Columns().Id).Scan(&list); err != nil {
		return nil, 0, err
	}

	return
}

// HistoryList 获取卡密历史记录列表
func (s *sLicenseKey) HistoryList(ctx context.Context, in *clientin.LicenseKeyHistoryListInp) (list []*clientin.LicenseKeyHistoryListModel, totalCount int, err error) {
	model := s.HistoryModel(ctx)

	// 尝试获取当前用户信息
	userId := contexts.GetUserId(ctx)
	if userId > 0 {
		// 已登录用户，查询关联到用户ID的卡密历史
		model = model.Where(dao.SysLicenseKeyHistory.Columns().UserId, userId)
	} else {
		// 未登录用户无法查看历史
		return nil, 0, gerror.New("未登录用户无法查看卡密历史")
	}

	// 按卡密ID筛选
	if in.LicenseKeyId > 0 {
		model = model.Where(dao.SysLicenseKeyHistory.Columns().LicenseKeyId, in.LicenseKeyId)
	}

	// 按操作类型筛选
	if in.ActionType != "" {
		model = model.Where(dao.SysLicenseKeyHistory.Columns().ActionType, in.ActionType)
	}

	// 按创建时间范围筛选
	if len(in.CreatedAt) == 2 && in.CreatedAt[0] != nil && in.CreatedAt[1] != nil {
		model = model.WhereBetween(dao.SysLicenseKeyHistory.Columns().CreatedAt, in.CreatedAt[0], in.CreatedAt[1])
	}

	// 执行查询
	totalCount, err = model.Count()
	if err != nil {
		return nil, 0, err
	}

	if totalCount == 0 {
		return nil, 0, nil
	}

	if err = model.Page(in.PageReq.Page, in.PageReq.PerPage).OrderDesc(dao.SysLicenseKeyHistory.Columns().Id).Scan(&list); err != nil {
		return nil, 0, err
	}

	return
}

// ApplyRefund 申请卡密退款
func (s *sLicenseKey) ApplyRefund(ctx context.Context, in *clientin.LicenseKeyApplyRefundInp) (res *clientin.LicenseKeyApplyRefundModel, err error) {
	var licenseKey *entity.SysLicenseKeys

	// 查询卡密是否存在
	if err = s.Model(ctx).Where(dao.SysLicenseKeys.Columns().Id, in.Id).Scan(&licenseKey); err != nil {
		return nil, err
	}

	if licenseKey == nil {
		return nil, gerror.New(consts.ErrLicenseKeyNotFound)
	}

	// 检查卡密状态，只有激活状态的卡密才能申请退款
	if licenseKey.Status != consts.LicenseKeyStatusActive {
		return nil, gerror.New("只有激活状态的卡密才能申请退款")
	}

	// 检查用户权限
	userId := contexts.GetUserId(ctx)
	if userId <= 0 {
		return nil, gerror.New("未登录用户无法申请退款")
	} else if licenseKey.UserId > 0 && licenseKey.UserId != userId {
		// 检查邮箱是否匹配
		var user *entity.SysUser
		err = dao.SysUser.Ctx(ctx).Where(dao.SysUser.Columns().Id, userId).Scan(&user)
		if err != nil {
			return nil, err
		}

		if user == nil || user.Email != licenseKey.Email {
			return nil, gerror.New("非卡密所有者无法申请退款")
		}
	}

	// 计算剩余有效期和退款金额
	now := gtime.Now()
	if licenseKey.ExpiresAt == nil || licenseKey.ActivatedAt == nil {
		return nil, gerror.New("卡密激活时间或过期时间异常")
	}

	// 如果已过期，不能退款
	if now.After(licenseKey.ExpiresAt) {
		return nil, gerror.New("卡密已过期，无法申请退款")
	}

	// 计算已使用天数和剩余天数
	totalDays := licenseKey.DurationDays
	usedSeconds := now.UnixNano() - licenseKey.ActivatedAt.UnixNano()
	usedDays := int(usedSeconds / (24 * 3600 * 1000000000))

	// 防止负数天数出现
	if usedDays < 0 {
		usedDays = 0
	}

	remainingDays := int(totalDays) - usedDays
	if remainingDays <= 0 {
		return nil, gerror.New("卡密已无剩余有效期，无法申请退款")
	}

	// 按照剩余天数比例计算退款金额
	refundAmount := licenseKey.Price * float64(remainingDays) / float64(totalDays)

	// 创建退款申请订单
	orderModel, err := service.SysOrder().Create(ctx, &clientin.OrderCreateInp{
		OrderType: consts.OrderTypeRefund,
		ProductId: int64(licenseKey.Id),
		Money:     refundAmount,
		Remark:    "卡密退款申请: " + in.RefundReason,
	})
	if err != nil {
		return nil, gerror.Wrap(err, consts.ErrLicenseKeyRefundFailed)
	}

	// 修改卡密状态为退款中
	_, err = s.Model(ctx).Where(dao.SysLicenseKeys.Columns().Id, licenseKey.Id).Data(g.Map{
		dao.SysLicenseKeys.Columns().Status:    consts.LicenseKeyStatusRefunded,
		dao.SysLicenseKeys.Columns().UpdatedAt: now,
	}).Update()
	if err != nil {
		return nil, gerror.Wrap(err, "更新卡密状态失败")
	}

	// 添加退款历史记录
	_, err = s.HistoryModel(ctx).Insert(entity.SysLicenseKeyHistory{
		LicenseKeyId:      licenseKey.Id,
		UserId:            uint64(licenseKey.UserId),
		ActionType:        consts.LicenseKeyActionRefund,
		Description:       "申请退款: " + in.RefundReason,
		DurationDaysAdded: -remainingDays,
		CreatedAt:         now,
	})
	if err != nil {
		g.Log().Error(ctx, "添加卡密退款历史记录失败:", err)
		// 不返回错误，不影响主流程
	}

	// 返回退款信息
	res = &clientin.LicenseKeyApplyRefundModel{
		RefundAmount: refundAmount,
		OrderId:      uint64(orderModel.Order.Id),
	}
	return
}

// 生成随机卡密字符串
func (s *sLicenseKey) generateKeyString() string {
	// 生成包含前缀的随机卡密字符串
	return "LK-" + gtime.Now().Format("YmdHis") + "-" + grand.S(8)
}
